package com.kongt.download;

import lombok.SneakyThrows;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.RandomAccessFile;
import java.util.concurrent.CountDownLatch;

/**
 * 每一个文件快的下载任务
 */
public class BlockDownloaderTask implements Runnable {

    /**
     * block开始位置
     */
    long start;
    /**
     * block结束位置
     */
    long end;

    /**
     * 目标文件
     */
    File destFile;

    /**
     * 下载配置
     */
    String downloadUrl;

    /**
     * 任务进度报告
     */
    AsyncHandler<Integer> asyncHandler;

    /**
     * 闭锁的使用
     */
    CountDownLatch countDownLatch;

    /**
     * 块下载错误阈值
     */
    int blockErrorC = 0;
    int hasRead = 0;

    public BlockDownloaderTask(File destFile, long start, long end, String downloadUrl, AsyncHandler<Integer> asyncHandler, CountDownLatch countDownLatch, int blockErrorC) {
        this.start = start;
        this.end = end;
        this.destFile = destFile;
        this.downloadUrl = downloadUrl;
        this.asyncHandler = asyncHandler;
        this.countDownLatch = countDownLatch;
        this.blockErrorC = blockErrorC;
    }

    @SneakyThrows
    @Override
    public void run() {
        while (blockErrorC > 0) {
            try {
                CloseableHttpClient httpClient = HttpClientBuilder.create().build();
                // 配置信息
                RequestConfig requestConfig = RequestConfig.custom()
                        // 设置连接超时时间(单位毫秒)
                        .setConnectTimeout(5000)
                        // 设置请求超时时间(单位毫秒)
                        .setConnectionRequestTimeout(5000)
                        // socket读写超时时间(单位毫秒)
                        .setSocketTimeout(5000)
                        // 设置是否允许重定向(默认为true)
                        .setRedirectsEnabled(false).build();
                HttpGet httpGet = new HttpGet(downloadUrl);
                httpGet.addHeader("Range", "bytes=" + start + "-" + end);
                httpGet.setConfig(requestConfig);
                CloseableHttpResponse response = httpClient.execute(httpGet);
                InputStream content = response.getEntity().getContent();
                RandomAccessFile randomAccessFile = new RandomAccessFile(destFile, "rws");
                //跳至写入位置
                randomAccessFile.seek(start);

                //缓冲区大小 1KB
                byte[] buffer = new byte[1024];
                int len;
                while ((len = content.read(buffer)) != -1) {
                    randomAccessFile.write(buffer, 0, len);
                    hasRead += len;
                    asyncHandler.handleResponse(len);
                }
                randomAccessFile.close();
                break;
            } catch (IOException | UnsupportedOperationException e) {
                e.printStackTrace();
                blockErrorC--;
                asyncHandler.handleResponse(-hasRead);
            }
        }
        countDownLatch.countDown();
    }
}
